#include "pch.h"
#include "dxrCommandListMgr.h"

CommandListMgr::Record::Record(ID3D12DevicePtr device, D3D12_COMMAND_LIST_TYPE type, ID3D12PipelineStatePtr state)
{
    HRESULT hResult = device->CreateCommandAllocator(type, IID_PPV_ARGS(&allocator));
    /*if (!SUCCEEDED(hResult))
    {
        hResult = device->GetDeviceRemovedReason();
    }*/
    hResult = device->CreateCommandList(0, type, allocator, state, IID_PPV_ARGS(&list));
    /*if (!SUCCEEDED(hResult))
    {
        hResult = device->GetDeviceRemovedReason();
    }*/
}

CommandListMgr::Record::~Record()
{
    list = nullptr;
    allocator = nullptr;
}

void CommandListMgr::Record::reset(ID3D12PipelineStatePtr state)
{
    allocator->Reset();
    list->Reset(allocator, state);
}

CommandListMgr::CommandListMgr(ID3D12DevicePtr device, D3D12_COMMAND_LIST_TYPE type, const wchar_t* name)
    : CommandListMgr(device, type, nullptr, name)
{
}

CommandListMgr::CommandListMgr(ID3D12DevicePtr device, D3D12_COMMAND_LIST_TYPE type, ID3D12PipelineStatePtr state, const wchar_t* name)
    : m_device(device)
    , m_type(type)
    , m_state(state)
    , m_name(name)
{
}

CommandListMgr::~CommandListMgr()
{
    m_in_use.clear();
    m_available.clear();
}

ID3D12GraphicsCommandList4Ptr CommandListMgr::get()
{
    ID3D12GraphicsCommandList4Ptr ret;
    if (!m_available.empty()) 
    {
        auto c = m_available.back();
        m_in_use.push_back(c);
        m_available.pop_back();
        ret = c->list;
    }
    else
    {
        auto c = std::make_shared<Record>(m_device, m_type, m_state);
        c->allocator->SetName(m_name.c_str());
        c->list->SetName(m_name.c_str());
        m_in_use.push_back(c);
        ret = c->list;
    }
    return ret;
}

void CommandListMgr::reset()
{
    for (auto& p : m_in_use)
        p->reset(m_state);
    m_available.insert(m_available.end(), m_in_use.begin(), m_in_use.end());
    m_in_use.clear();
}